"""
-------------------------------
- File_Name: exceptions.py
- Date: 2025/2/16
- Author: yangzhide
- Email: xxzjyzd@126.com
- Description: 全局异常类
-------------------------------
"""

from fastapi import HTTPException, FastAPI
from typing import Optional, Dict, Union
from fastapi.exceptions import RequestValidationError, ResponseValidationError
from tortoise.exceptions import DoesNotExist, IntegrityError, FieldError
from starlette import status
from starlette.requests import Request
from starlette.responses import JSONResponse
from app.utils.responseUtil import ResponseUtil



class AuthenticationError(HTTPException):
    """统一认证异常类"""

    def __init__(
            self,
            code: int = 9999,
            msg: str = "认证失败",
            headers: Optional[Dict[str, str]] = None
    ):
        super().__init__(
            status_code=code,
            detail=msg,
            headers=headers
        )
        self.code = code  # 保留自定义code字段


def register_exception_handler(app: FastAPI):
    # 添加认证处理器
    @app.exception_handler(AuthenticationError)
    async def auth_exception_handler(request: Request, exc: AuthenticationError):
        response = ResponseUtil.error_response(code=exc.code, msg=exc.detail)
        return JSONResponse(status_code=exc.code, content=response)  # 状态非200符合fastapi的docs文档outh2校验
        # return JSONResponse(status_code=200, content=response)  # 状态200，响应前端错误信息提取

    # 新增HTTPException处理器
    @app.exception_handler(HTTPException)
    async def http_exception_handler(request: Request, exc: HTTPException):
        response = ResponseUtil.error_response(code=exc.status_code, msg=exc.detail)
        return JSONResponse(status_code=200, content=response)

    # tortoise 数据库完整性错误
    @app.exception_handler(IntegrityError)
    async def integrity_exception_handler(request: Request, exc: IntegrityError):
        response = ResponseUtil.error_response(code=400, msg=f"违反约束条件，与主键或非空约束冲突;exc: {exc}")
        return JSONResponse(status_code=200, content=response)

    @app.exception_handler(FieldError)
    async def field_exception_handler(request: Request, exc: FieldError):
        response = ResponseUtil.error_response(code=503, msg=f"内部字段错误，请检查;exc:{exc}")
        return JSONResponse(status_code=200, content=response)

    # 资源不存在
    @app.exception_handler(DoesNotExist)
    async def does_not_exist_exception_handler(request: Request, exc: DoesNotExist):
        response = ResponseUtil.error_response(code=404, msg=f"资源不存在; exc: {exc}")
        return JSONResponse(status_code=200, content=response)

    # 新增的Pydantic验证异常处理器
    @app.exception_handler(RequestValidationError)
    @app.exception_handler(ResponseValidationError)
    async def validation_exception_handler(request: Request,exc: Union[RequestValidationError, ResponseValidationError]):
        # 确定状态码和消息
        if isinstance(exc, RequestValidationError):
            status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
            msg = "请求参数验证失败"
        elif isinstance(exc, ResponseValidationError):
            status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
            msg = "序列化验证失败"
        else:
            status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
            msg = "内部服务器错误"

        # 收集错误详情
        errors = []
        error = exc.errors()[0]  # 只读取第一条错误即可
        loc = error["loc"]
        # 将位置信息转换为字符串（例如："body.user.name"）
        loc_str = ".".join(map(str, loc))
        errors.append({
            "loc": loc_str,
            "msg": error.get("msg", "未知错误"),
            "type": error.get("type", "invalid")
        })
        response = ResponseUtil.error_response(code=status_code, msg=f"{msg},错误详情：{errors}", )
        return JSONResponse(status_code=200, content=response, )

    # 新增全局其他异常————必须放最后
    @app.exception_handler(Exception)
    async def universal_exception_handler(request: Request, exc: Exception):
        """
        捕获所有未被处理的异常（如 KeyError, AttributeError 等）
        """
        response = ResponseUtil.error_response(code=500, msg=f"服务器意外错误;exc：{exc}")
        return JSONResponse(status_code=200, content=response)